package org.tangerinejunction.imstats.data;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Calendar;

import prefuse.data.Graph;
import prefuse.data.Table;
import prefuse.data.tuple.TableTuple;

/**
 * Frequently a single user will have multiple instant messaging accounts,
 * on different protocols or for different uses.
 * Usually when a user wants to analyze the data, they don't care about
 * individual accounts as much as the individuals or entities that
 * operate a set of accounts.  The Entity class allows us to consider
 * the data for a set of Accounts as though it were one Account, 
 * and to apply a name to the set.
 * 
 * @author meganthorsen
 */
public class Entity extends TableTuple implements Comparable<Entity>, Externalizable
{
	private static final long serialVersionUID = 5667679118216525828L;
	
	public static final String NAME_KEY = "Group name";
	public static final String ACCOUNTS_KEY = "Accounts";
	public static final String FILTERED = Account.FILTERED;
	
	public Entity()
	{
		super();
	}
	
	/**
	 * 
	 * @param table	the Prefuse Table backing Entities
	 * @param graph	the Prefuse Graph backing Entities
	 * @param row	the row in the Prefuse Table associated with this Entity
	 * @param name	the alias provided for this Entity
	 */
	public void init(Table table, Graph graph, int row, String name)
	{
		init(table, graph, row);
		setString(NAME_KEY, name);
		set(ACCOUNTS_KEY, new AccountSet());
		set(FILTERED, false);
	}
	
	/**
	 * 
	 * @return	the name of this Entity
	 */
	public String getName()
	{
		return getString(NAME_KEY);
	}
	
	/**
	 * 
	 * @return	the set of Accounts associated with this Entity
	 */
	public AccountSet getAccounts()
	{
		return (AccountSet)get(ACCOUNTS_KEY);
	}
	
	/**
	 * 
	 * @return	whether this Entity has been filtered from charts
	 */
	public boolean getFiltered()
	{
		return (Boolean)get(FILTERED);
	}
	
	public Calendar getMinLogDate() 
	{
	    Calendar minLogDate = null;
	    for (Account a : getAccounts())
	    {
	        if (minLogDate == null || a.getMinLogDate().before(minLogDate))
	            minLogDate = a.getMinLogDate();
	    }
	    return minLogDate;
	}
	
	/**
	 * 
	 * @param account	the Account to add to this Entity's AccountSet
	 */
	public void addAccount(Account account)
	{
		AccountSet accounts = getAccounts();
		if (accounts == null)
			accounts = new AccountSet();
		if (!accounts.contains(account))
		{
			accounts.add(account);
			account.set(Account.ENTITY_KEY, this);
		}
		set(ACCOUNTS_KEY, accounts);
	}
	
	/**
	 * 
	 * @param account	the Account to remove from this Entity's AccountSet
	 */
	public void removeAccount(Account account)
	{
		AccountSet accounts = getAccounts();
		if (accounts == null)
			accounts = new AccountSet();
		for (Account a : accounts)
		{
			if (account.compareTo(a) == 0)
			{
				accounts.remove(a);
				break;
			}
		}
		set(ACCOUNTS_KEY, accounts);
	}
	
	public String toString()
	{
		return getName();
	}

	public int compareTo(Entity entity) 
	{
		return this.getName().compareTo(entity.getName());
	}

	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException 
	{
		
	}

	public void writeExternal(ObjectOutput out) throws IOException 
	{
		/*
		out.writeObject(getName());
		out.writeObject(getAccounts());
		*/
	}
}
